#include <iostream>
#include <vector>
#include <string>
#include <mutex>
#include <thread>
#include <time.h>
using namespace std;

// class HeapOnly
// {
//     int _val;
//     // 把构造和拷贝构造设置成私有
//     HeapOnly(int val = 0)
//         : _val(val)
//     {
//     }
//     HeapOnly(const HeapOnly &obj) {}

// public:
//     static HeapOnly *CreateObject(int val = 0)
//     {
//         return new HeapOnly(val);
//     }
// };

// int main()
// {
//     // HeapOnly obj;
//     HeapOnly *pobj1 = HeapOnly::CreateObject(10);
//     // HeapOnly obj(*pobj1);

//     return 0;
// }

// class HeapOnly
// {
//     int _val;
//     // 把析构设置成私有
//     ~HeapOnly()
//     {
//         cout << "~HeapOnly()" << endl;
//     }

// public:
//     HeapOnly(int val = 0)
//         : _val(val)
//     {
//     }

//     HeapOnly(const HeapOnly &obj) {}

//     void DestroyObj()
//     {
//         // delete this;
//     }
// };

// int main()
// {
//     // HeapOnly obj;
//     HeapOnly *pobj = new HeapOnly(10);
//     // HeapOnly obj(*pobj);
//     pobj->DestroyObj();

//     return 0;
// }

// class StackOnly
// {
//     int _val;
//     StackOnly(int val = 0)
//         : _val(val)
//     {
//     }

//     StackOnly(const StackOnly &obj)
//         : _val(obj._val)
//     {
//     }

// public:
//     static StackOnly CreateObj(int val = 0)
//     {
//         StackOnly obj(val);
//         return obj;
//     }

//     StackOnly(StackOnly&& obj)
//     {
//         ::swap(_val, obj._val);
//     }

// };

// int main()
// {
//     StackOnly obj = StackOnly::CreateObj(10);
//     // StackOnly *pobj = new StackOnly(10);
//     StackOnly *pobj1 = new StackOnly(move(obj)); //还是可以在堆上创建对象
//     cout << "aaa" << endl;
//     return 0;
// }

// class StackOnly
// {
//     int _val;

//     void* operator new(size_t t);
// public:
//     StackOnly(int val = 0)
//         : _val(val)
//     {
//     }

//     StackOnly(const StackOnly &obj)
//         : _val(obj._val)
//     {
//     }
// };

// int main()
// {
//     StackOnly obj(10);
//     StackOnly obj1(obj);
//     StackOnly *pobj = new StackOnly(10);
//     StackOnly *pobj = new StackOnly(obj);

//     return 0;
// }

// // 饿汉模式1
// class Singleton
// {
//     // 成员变量
//     vector<string> _dir;
//     // 该类的静态指针，提供一个访问单例的全局访问点
//     static Singleton *s_ins;
//     // 静态互斥锁，保证多线程互斥访问该单例
//     mutex s_mtx;
//     // 静态的内部类对象，该对象析构时会顺便析构单例
//     struct GC
//     {
//         ~GC()
//         {
//             if (s_ins != nullptr)
//             {
//                 delete s_ins;
//                 s_ins = nullptr;
//             }
//         }
//     };
//     static GC s_gc;
//     // 私有构造和拷贝构造，保证系统中该类只有一个实例
//     Singleton()
//     {
//         cout << "Singleton()" << endl;
//     };
//     Singleton(const Singleton &st);
//     ~Singleton()
//     {
//         // 单例对象的析构一般会做一些持久化操作（数据落盘）
//         // ......
//         cout << "~Singleton()" << endl;
//     }

// public:
//     // 提供一个静态成员函数，用于获取全局访问点（静态指针）
//     static Singleton *GetInstance()
//     {
//         return s_ins;
//     }

//     void Add(const string &name)
//     {
//         s_mtx.lock();
//         _dir.push_back(name);
//         s_mtx.unlock();
//     }

//     void Print()
//     {
//         s_mtx.lock();
//         for (auto &name : _dir)
//         {
//             cout << name << endl;
//         }
//         s_mtx.unlock();
//     }
//     // 一般单例对象的生命周期随进程，系统会在进程退出时释放其内存，不需要中途析构单例对象
//     // 不过在一些特殊场景下，可能需要进行显示释放，比如需要在单例析构前做一些持久化操作
//     // static void DelInstance()
//     // {
//     //     s_mtx.lock();
//     //     if (s_ins != nullptr)
//     //     {
//     //         delete s_ins;
//     //         s_ins = nullptr;
//     //     }
//     //     s_mtx.unlock();
//     // }
// };

// // 程序启动时(main函数之前)创建
// Singleton *Singleton::s_ins = new Singleton;
// // mutex Singleton::s_mtx;
// Singleton::GC Singleton::s_gc;

// 饿汉模式2
// class Singleton
// {
//     // 成员变量
//     vector<string> _dir;
//     // 该类的静态对象，提供一个访问单例的全局访问点
//     static Singleton s_ins;
//     // 静态互斥锁，保证多线程互斥访问该单例
//     mutex s_mtx;
//     // 私有构造和拷贝构造，保证系统中该类只有一个实例
//     Singleton()
//     {
//         cout << "Singleton()" << endl;
//     };
//     Singleton(const Singleton &st);

// public:
//     // 提供一个静态成员函数，用于获取全局访问点（静态对象）
//     static Singleton &GetInstance()
//     {
//         return s_ins;
//     }

//     void Add(const string &name)
//     {
//         s_mtx.lock();
//         _dir.push_back(name);
//         s_mtx.unlock();
//     }

//     void Print()
//     {
//         s_mtx.lock();
//         for (auto &name : _dir)
//         {
//             cout << name << endl;
//         }
//         s_mtx.unlock();
//     }

//     ~Singleton()
//     {
//         // 单例对象的析构一般会做一些持久化操作（数据落盘）
//         // ......
//         cout << "~Singleton()" << endl;
//     }
// };

// // 程序启动时(main函数之前)创建
// Singleton Singleton::s_ins;

// int main()
// {
//     // 系统中该类只有一个实例，不允许通过任何方式实例化
//     // Singleton st;
//     // static Singleton st1;
//     // Singleton* pst = new Singleton;
//     //  Singleton st(*(Singleton::GetInstance()));

//     // 单线程场景
//     // Singleton::GetInstance()->Add("张三");
//     // Singleton::GetInstance()->Add("李四");
//     // Singleton::GetInstance()->Add("王五");

//     // Singleton::GetInstance()->Print();

//     // 多线程场景
//     int n = 6;
//     srand((unsigned int)time(nullptr));
//     thread t1([n]() mutable
//               {
//         while(n--)
//         {
//             Singleton::GetInstance()->Add("线程1：" + to_string(rand()));
//             this_thread::sleep_for(chrono::milliseconds(10));
//         } });

//     thread t2([n]() mutable
//               {
//         while(n--)
//         {
//             Singleton::GetInstance()->Add("线程2：" + to_string(rand()));
//             this_thread::sleep_for(chrono::milliseconds(10));
//         } });

//     t1.join();
//     t2.join();
//     // Singleton::GetInstance().~Singleton();
//     Singleton::GetInstance()->Print();
//     // Singleton::DelInstance();
// }

// 懒汉模式1
class Singleton
{
    // 成员变量
    vector<string> _dir;
    // 该类的静态指针，提供一个访问单例的全局访问点
    static Singleton *s_ins;
    // 静态互斥锁，保证多线程互斥地创建和访问该单例
    static mutex s_mtx;
    // 静态的内部类对象，该对象析构时会顺便析构单例
    struct GC
    {
        ~GC()
        {
            if (s_ins != nullptr)
            {
                delete s_ins;
                s_ins = nullptr;
            }
        }
    };
    static GC gc;
    // 私有构造和拷贝构造，保证系统中该类只有一个实例
    Singleton()
    {
        cout << "Singleton()" << endl;
    };
    Singleton(const Singleton &st);
    ~Singleton()
    {
        // 单例对象的析构一般会做一些持久化操作（数据落盘）
        // ......
        cout << "~Singleton()" << endl;
    }

public:
    static Singleton *GetInstance()
    {
        // 懒汉模式：在第一次访问实例时创建
        // 双检查加锁
        if (s_ins == nullptr) // 第一道检查：提高效率，不需要每次获取单例都加锁解锁
        {
            s_mtx.lock();
            if (s_ins == nullptr) // 第二道检查：保证线程安全和只new一次
            {
                s_ins = new Singleton;
            }
            s_mtx.unlock();
        }
        return s_ins;
    }

    void Add(const string &name)
    {
        s_mtx.lock();
        _dir.push_back(name);
        s_mtx.unlock();
    }

    void Print()
    {
        s_mtx.lock();
        for (auto &name : _dir)
        {
            cout << name << endl;
        }
        s_mtx.unlock();
    }

    // 一般单例对象的生命周期随进程，系统会在进程退出时释放其内存，不需要中途析构单例对象
    // 不过在一些特殊场景下，可能需要进行显示释放，比如需要在单例析构前做一些持久化操作
    static void DelInstance()
    {
        s_mtx.lock();
        if (s_ins != nullptr)
        {
            delete s_ins;
            s_ins = nullptr;
        }
        s_mtx.unlock();
    }
};

Singleton *Singleton::s_ins = nullptr;
mutex Singleton::s_mtx;
Singleton::GC Singleton::gc;

// 懒汉模式2
// class Singleton
// {
//     // 成员变量
//     vector<string> _dir;
//     // 静态互斥锁，保证多线程互斥地创建和访问该单例
//     mutex s_mtx;
//     // 私有构造和拷贝构造，保证系统中该类只有一个实例
//     Singleton()
//     {
//         cout << "Singleton()" << endl;
//     };
//     Singleton(const Singleton &st);
//     ~Singleton()
//     {
//         // 单例对象的析构一般会做一些持久化操作（数据落盘）
//         // ......
//         cout << "~Singleton()" << endl;
//     }
// public:
//     static Singleton *GetInstance()
//     {
//         // C++11之前，这里不能保证初始化静态对象的线程安全问题
//         // C++11之后，这里可以保证初始化静态对象的线程安全问题
//         static Singleton s_ins;
//         return &s_ins;
//     }

//     void Add(const string &name)
//     {
//         s_mtx.lock();
//         _dir.push_back(name);
//         s_mtx.unlock();
//     }

//     void Print()
//     {
//         s_mtx.lock();
//         for (auto &name : _dir)
//         {
//             cout << name << endl;
//         }
//         s_mtx.unlock();
//     }

//     // 一般单例对象的生命周期随进程，系统会在进程退出时释放其内存，不需要中途析构单例对象
//     // 不过在一些特殊场景下，可能需要进行显示释放
//     // static void DelInstance()
//     // {
//     //     s_mtx.lock();
//     //     if (s_ins != nullptr)
//     //     {
//     //         delete s_ins;
//     //         s_ins = nullptr;
//     //     }
//     //     s_mtx.unlock();
//     // }

    
// };

// mutex Singleton::s_mtx;

int main()
{
    // 系统中该类只有一个实例，不允许通过任何方式实例化
    // Singleton st;
    // static Singleton st1;
    // Singleton* pst = new Singleton;
    // Singleton st(*(Singleton::GetInstance()));

    // 单线程场景
    // Singleton::GetInstance()->Add("张三");
    // Singleton::GetInstance()->Add("李四");
    // Singleton::GetInstance()->Add("王五");

    // Singleton::GetInstance()->Print();

    // 多线程场景
    int n = 6;
    srand((unsigned int)time(nullptr));
    thread t1([n]() mutable
              {
        while(n--)
        {
            Singleton::GetInstance()->Add("线程1：" + to_string(rand()));
            this_thread::sleep_for(chrono::milliseconds(10));
        } });

    thread t2([n]() mutable
              {
        while(n--)
        {
            Singleton::GetInstance()->Add("线程2：" + to_string(rand()));
            this_thread::sleep_for(chrono::milliseconds(10));
        } });

    t1.join();
    t2.join();
    
    Singleton::DelInstance();

    Singleton::GetInstance()->Print();
    // Singleton::DelInstance();
}